﻿using AutoCommunication.Base;
using AutoCommunication.Enums;
using AutoCommunication.Helper;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Net;
using System.Net.Sockets;

namespace AutoCommunication.Clients
{
    /// <summary>
    /// 西门子:
    /// </summary>
    [DisplayName("西门子Plc"), Description("描述")]
    public class DevSiemens : BaseSocketDevice<VarableSiemens>
    {
        public DevSiemens()
        {
        }

        #region 特有属性

        /// <summary>
        /// CPU版本
        /// </summary>
        [JsonProperty("型号"), DisplayName("设备型号"), Category("设备信息")]
        public SiemensVersion Version { get; set; } = SiemensVersion.S7_1200;

        /// <summary>
        /// 插槽号:一般1200 1500都为0;300系列默认为2;400系列默认为3:
        /// <para>指的是CPU的插槽位置,而不是通讯模块的位置,所以一般都是固定的</para>
        /// </summary>
        [Description("插槽号:一般1200 1500都为0;300系列默认为2;400系列默认为3"), DisplayName("插槽号"), Category("设备信息")]
        [JsonProperty("插槽号")]
        public byte Slot { get; set; }

        /// <summary>
        /// 机架号:一般都为0;除非超大的系统,可能一个机架不够,不然都够了
        /// </summary>
        [JsonProperty("机架号"), DisplayName("机架号"), Category("设备信息"), Description("一般都为0;除非超大的系统,可能一个机架不够,不然都够了")]
        public byte Rack { get; set; }

        [JsonProperty("PDU"), DisplayName("PDU"), Category("系统默认参数")]
        public int Pdu { get; set; } = 240;

        #endregion 特有属性

        #region 重写属性

        [JsonProperty("设备名")]
        [DisplayName("设备名"), Category("设备信息")]
        public override string Name { get; set; } = "西门子PLC";

        [JsonProperty("字节格式"), DisplayName("字节格式"), Category("设备信息")]
        public override EndianFormat Format { get; set; } = EndianFormat.DCBA;

        /// <summary>
        /// IP地址
        /// </summary>
        [JsonProperty("IP地址"), DisplayName("IP地址"), Category("设备信息")]
        public override string IpAddress { get; set; } = "192.168.0.120";

        /// <summary>
        /// IP地址
        /// </summary>
        [JsonProperty("端口"), DisplayName("端口号"), Category("设备信息")]
        public override int Port { get; set; } = 102;

        #endregion 重写属性

        [Obsolete]
        protected override Result Connect()
        {
            var result = new Result();
            socket?.SafeClose();
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            try
            {
                //超时时间设置
                socket.ReceiveTimeout = Timeout;
                socket.SendTimeout = Timeout;

                //连接
                socket.Connect(IpEndPoint);

                var Command1 = SiemensConstant.Command1;
                var Command2 = SiemensConstant.Command2;

                switch (Version)
                {
                    case SiemensVersion.S7_200:
                        Command1 = SiemensConstant.Command1_200;
                        Command2 = SiemensConstant.Command2_200;
                        break;

                    case SiemensVersion.S7_200Smart:
                        Command1 = SiemensConstant.Command1_200Smart;
                        Command2 = SiemensConstant.Command2_200Smart;
                        break;

                    case SiemensVersion.S7_300:
                        Command1[21] = (byte)((Rack * 0x20) + Slot); //0x02;
                        break;

                    case SiemensVersion.S7_400:
                        Command1[21] = (byte)((Rack * 0x20) + Slot); //0x03;
                        Command1[17] = 0x00;
                        break;

                    case SiemensVersion.S7_1200:
                        Command1[21] = (byte)((Rack * 0x20) + Slot); //0x00;
                        break;

                    case SiemensVersion.S7_1500:
                        Command1[21] = (byte)((Rack * 0x20) + Slot); //0x00;
                        break;

                    default:
                        Command1[18] = 0x00;
                        break;
                }

                result.Requst = string.Join(" ", Command1.Select(t => t.ToString("X2")));
                //第一次初始化指令交互
                socket.Send(Command1);

                var socketReadResul = socket.Read(SiemensConstant.InitHeadLength);
                if (!socketReadResul.IsSucceed)
                    return socketReadResul;
                var head1 = socketReadResul.Value;

                int GetContentLength(byte[] head)
                {
                    if (head?.Length >= 4)
                        return head[2] * 256 + head[3] - 4;
                    else
                        throw new ArgumentException("请传入正确的参数");
                }

                socketReadResul = socket.Read(GetContentLength(head1));
                if (!socketReadResul.IsSucceed)
                    return socketReadResul;
                var content1 = socketReadResul.Value;

                result.Response = string.Join(" ", head1.Concat(content1).Select(t => t.ToString("X2")));

                result.Requst2 = string.Join(" ", Command2.Select(t => t.ToString("X2")));
                //第二次初始化指令交互
                socket.Send(Command2);

                socketReadResul = socket.Read(SiemensConstant.InitHeadLength);
                if (!socketReadResul.IsSucceed)
                    return socketReadResul;
                var head2 = socketReadResul.Value;

                socketReadResul = socket.Read(GetContentLength(head2));
                if (!socketReadResul.IsSucceed)
                    return socketReadResul;
                var content2 = socketReadResul.Value;
                var pdu = content2.Skip(21).Take(2).Reverse().ToArray();
                Pdu = BitConverter.ToUInt16(pdu, 0);
                result.Response2 = string.Join(" ", head2.Concat(content2).Select(t => t.ToString("X2")));
            }
            catch (Exception ex)
            {
                socket?.SafeClose();
                result.IsSucceed = false;
                result.Err = ex.Message;
                result.ErrCode = 408;
                result.Exception = ex;
                Loger?.Invoke("连接失败", ex);
            }
            return result.EndTime();
        }//ok

        protected override List<byte[]> GetReadCommand(Group<VarableSiemens> group)
        {
            List<byte[]> result = new();
            var info = group.Varablelist[0];
            var count = group.Length;
            var start = group.StartByteAddress;
            while (count > 0)
            {
                int length = Math.Min(count, Pdu - 18);
                byte[] command = new byte[31];//读取命令的报文固定是32个字节长度
                command[0] = 0x03;
                command[1] = 0x00;//[0][1]固定报文头

                command[2] = 0x00;// (byte)(command.Length / 256);
                command[3] = 0x1F;// (byte)(command.Length % 256);//[2][3]为整个读取请求长度为0x1F= 31个字节   备注:优化可以一下读取多个区

                command[4] = 0x02;
                command[5] = 0xF0;
                command[6] = 0x80;//COTP
                command[7] = 0x32;//协议ID
                command[8] = 0x01;//1客户端发送命令 3服务器回复命令
                command[9] = 0x00;
                command[10] = 0x00;//[4]-[10]为固定参数

                command[11] = 0x00;
                command[12] = 0x01;//[11][12]两个字节，标识序列号，回复报文相同位置和这个完全一样；范围是0~65535

                command[13] = 0x00;//
                command[14] = 0x0E;// 0E=14;他其实真实含义是报文中参数的字节个数,也就是从command[16]之后;因为command[17-30]的个数为14,所以这里是14;因为涉及同时读取多个存储区的话,可以在后面继续跟,我们这儿始终一次报文只读一个区,所以,固定14

                command[15] = 0x00;
                command[16] = 0x00;//读取的时候,固定这个就好,写入的时候,这里是写入的字节个数+4

                command[17] = 0x04;//04表示读 05表示写,所以这里也固定了
                command[18] = 0x01;// (byte)group.Length;//读取存储区个数,我们一次只读一个,所以也固定了

                command[19] = 0x12;//固定 variable specification
                command[20] = 0x0A;//固定 Length of following address specification
                command[21] = 0x10;//固定 Syntax Id: S7ANY
                command[22] = 0x02;//固定为02;解释:01表示按照bit位一个一个读取;02表示按照字节一个一个读取;这里没有怎么理解到,资料各种解释都有,一般都是02就对了
                command[23] = (byte)(length / 256);
                command[24] = (byte)(length % 256);//[23][24]我们要读取多少个字节，以byte为单位；

                command[25] = (byte)(info.DBNum / 256);
                command[26] = (byte)(info.DBNum % 256);//DB块的编号,如果不是DB区,这个参数可以随意设置,一般设置0就好

                command[27] = (byte)info.SiemensStore;//访问数据块的类型
                command[28] = (byte)(start * 8 / 256 / 256 % 256);
                command[29] = (byte)(start * 8 / 256 % 256);
                command[30] = (byte)(start * 8 % 256);//[28][29][30]访问DB块的偏移量,这里是按照bit位置来计算的,去掉西门子的优化块访问就能看到这个了

                count -= length;
                start -= length;
                result.Add(command);
            }
            return result;
        }//0k

        protected override byte[] GetWriteCommand(Group<VarableSiemens> group)
        {
            var info = group.Varablelist[0];
            //前19个固定的、16为Item长度  一共35 个
            //group.Length 为要写入的字节个数
            byte[] command = new byte[35 + group.Length];

            command[0] = 0x03;
            command[1] = 0x00;//[0][1]固定报文头

            command[2] = (byte)((group.Length + 35) / 256);
            command[3] = (byte)((group.Length + 35) % 256);//[2][3]整个报文请求长度:固定的有35个+我们要写入多少个字节

            command[4] = 0x02;
            command[5] = 0xF0;
            command[6] = 0x80;
            command[7] = 0x32;//protocol Id
            command[8] = 0x01;//1  客户端发送命令 3 服务器回复命令
            command[9] = 0x00;
            command[10] = 0x00;//[4]-[10]为固定参数;有资料介绍[9][10]为 redundancy identification (冗余的识别)

            command[11] = 0x00;
            command[12] = 0x01;//[11][12]随意设定;回复报文相同位置和这个完全一样；范围是0~65535

            command[13] = 0x00;// (byte)((12 * group.Varablelist.Count + 2) / 256);
            command[14] = 0x0E;// 0E=14;他其实真实含义是报文中参数的字节个数,也就是从command[16]之后;因为command[17-30]的个数为14,所以这里是14;因为涉及同时读取多个存储区的话,可以在后面继续跟,我们这儿始终一次报文只读一个区,所以,固定14

            command[15] = (byte)((group.Length + 4) / 256);
            command[16] = (byte)((group.Length + 4) % 256);//我们需要写入多少个字节+4;

            //Parameter
            command[17] = 0x05;//04读 05写 Function Write
            command[18] = 0x01;//写入多少个存储区,我们始终一次只写入一个,所以固定01
            command[19] = 0x12;
            command[20] = 0x0A;
            command[21] = 0x10;//[19]-[21]固定
            command[22] = group.Varablelist.First().DataType == DataTypeEnum.Bool ? (byte)0x01 : (byte)0x02;//写入方式，1是按位，2是按字
            command[23] = (byte)(group.Length / 256);
            command[24] = (byte)(group.Length % 256);//写入数据个数;解释,前面command[22]写入方式为bit的时候,就是写入多少个bit;方式为byte的时候,这里就表示多少个字节
            command[25] = (byte)(info.DBNum / 256);
            command[26] = (byte)(info.DBNum % 256);//DB块的编号
            command[27] = (byte)info.SiemensStore;//写到那一个存存储区
            var stb = group.Varablelist.First().StartByteAddress;
            var stbit = group.Varablelist.First().BitOffset;

            command[28] = (byte)((group.StartByteAddress * 8 + stbit) / 256 / 256 % 256); ;
            command[29] = (byte)((group.StartByteAddress * 8 + stbit) / 256 % 256);
            command[30] = (byte)((group.StartByteAddress * 8 + stbit) % 256);//[28][29][30]访问DB块的偏移量

            int isbit = group.Varablelist.First().DataType == DataTypeEnum.Bool ? 1 : 8;
            command[31] = 0x00;
            command[32] = isbit == 1 ? (byte)0x03 : (byte)0x04;// 03bit（位）04 byte(字节)  貌似这里跟command[22]功能重合了,why?

            command[33] = (byte)(group.Length * isbit / 256);
            command[34] = (byte)(group.Length * isbit % 256);//把需要写入的数据,计算成有多少个bit位
            if (group.Varablelist.First().DataType == DataTypeEnum.Bool)
            {
                command[35] = Convert.ToBoolean(group.Varablelist.First().WriteValue) ? (byte)0x01 : (byte)0x00;
            }
            else
            {
                var vals = Convert.ToDouble(group.Varablelist.First().WriteValue).ToBytes(group.Varablelist.First().DataType, Format);
                vals.CopyTo(command, 35);
            }
            return command;
        }//0k

        protected override Result<byte[]> SendAndRevice(byte[] command)
        {
            int GetContentLength(byte[] head)
            {
                if (head?.Length >= 4)
                    return head[2] * 256 + head[3] - 4;
                else
                    throw new ArgumentException("请传入正确的参数");
            }
            //从发送命令到读取响应为最小单元，避免多线程执行串数据（可线程安全执行）
            lock (Readlock)
            {
                Result<byte[]> result = new Result<byte[]>();
                try
                {
                    socket.Send(command);
                    var socketReadResul = socket.Read(SiemensConstant.InitHeadLength);//读取报文的头部,可以之后后续还有多少个字节的数据
                    if (!socketReadResul.IsSucceed)
                        return socketReadResul;
                    var headPackage = socketReadResul.Value;

                    socketReadResul = socket.Read(GetContentLength(headPackage));//读取真实的数据
                    if (!socketReadResul.IsSucceed)
                        return socketReadResul;
                    var dataPackage = socketReadResul.Value;

                    result.Value = headPackage.Concat(dataPackage).ToArray();//合并包头和数据
                    var lbytes = new byte[2] { result.Value[3], result.Value[2] };
                    var length = BitConverter.ToUInt16(lbytes, 0);
                    if (length >= 25)
                    {
                        result.ResponseData = new byte[length - 25];
                        Array.Copy(result.Value, 25, result.ResponseData, 0, length - 25);
                    }
                    return result.EndTime();
                }
                catch (Exception ex)
                {
                    result.IsSucceed = false;
                    result.Err = ex.Message;
                    result.AddErr2List();
                    return result.EndTime();
                }
            }
        }//ok

        protected override Result CheckDeviceParameters()
        {
            Result result = new Result();
            if (IPAddress.TryParse(IpAddress, out IPAddress ip))
            {
                IpEndPoint = new IPEndPoint(ip, Port);
            }
            else
            {
                result.IsSucceed = false;
                result.Err = "IP地址格式错误";
            }

            switch (Version)
            {
                case SiemensVersion.None:
                    break;

                case SiemensVersion.S7_200:
                    break;

                case SiemensVersion.S7_200Smart:
                    break;

                case SiemensVersion.S7_300:
                    Slot = 02;
                    break;

                case SiemensVersion.S7_400:
                    Slot = 03;
                    break;

                case SiemensVersion.S7_1200:
                    Slot = 00;
                    break;

                case SiemensVersion.S7_1500:
                    Slot = 00;
                    break;

                default:
                    break;
            }
            return result;
        }

        protected override Result CheckOther()
        {
            return new Result();
        }//ok

        protected override List<Group<VarableSiemens>> Group(List<VarableSiemens> AllVarable)
        {
            Result result = new Result();
            List<Group<VarableSiemens>> GroupList = new List<Group<VarableSiemens>>();
            var g1 = AllVarable.GroupBy(x => x.SiemensStore);//存储区

            foreach (var group1 in g1)
            {
                Group<VarableSiemens> gp = new Group<VarableSiemens>();
                var order = group1.OrderBy(x => x.StartByteAddress);
                gp.StartByteAddress = order.First().StartByteAddress;
                gp.Length = Common.GetBytelength(order.First());
                GroupList.Add(gp);
                foreach (VarableSiemens item in order)
                {
                    if (Common.GetBytelength(item) > Pdu - 18)
                    {
                        Group<VarableSiemens> gp2 = new Group<VarableSiemens>();
                        gp2.StartByteAddress = item.StartByteAddress;
                        gp2.Length = Common.GetBytelength(item);
                        GroupList.Add(gp2);
                        GroupList.Last().Varablelist.Add(item);
                    }
                    else if (item.StartByteAddress - GroupList.Last().StartByteAddress + Common.GetBytelength(item) < Pdu - 18)
                    {
                        GroupList.Last().Length = item.StartByteAddress - GroupList.Last().StartByteAddress + Common.GetBytelength(item);
                        GroupList.Last().Varablelist.Add(item);
                    }
                    else
                    {
                        Group<VarableSiemens> gp2 = new Group<VarableSiemens>();
                        gp2.StartByteAddress = item.StartByteAddress;
                        gp2.Length = Common.GetBytelength(item);
                        GroupList.Add(gp2);
                        GroupList.Last().Varablelist.Add(item);
                    }
                }
            }

            return GroupList;
        }

        protected override Result AutoReadGroup()
        {
            Result result = new Result();
            return result;
        }
    }

    #region 派生的变量和变量组

    /// <summary>
    /// 地址形式:
    /// <para>DB1.0.0、DB1.4（非PLC地址）</para>
    /// <para>DB1.DBX0.0、DB1.DBD4（标准PLC地址）</para>
    /// <para>I0.0、V1004的情况（非PLC地址）</para>
    /// <para>VB1004的情况（标准PLC地址）</para>
    /// <para></para>
    /// </summary>
    public class VarableSiemens : BaseVariable
    {
        /// <summary>
        ///
        /// </summary>
        public VarableSiemens()
        {
        }

        /// <summary>
        /// 地址解析,非常重要的方法
        /// </summary>
        /// <returns></returns>
        public override Result AddressAnalysis()
        {
            int GetBeingAddress(string address)
            {
                //去掉V1025 前面的V
                //address = address.Substring(1);
                //I1.3地址的情况
                if (address.IndexOf('.') < 0)
                    return int.Parse(address);
                else
                {
                    string[] temp = address.Split('.');
                    return Convert.ToInt32(temp[0]);
                }
            }
            int GetBitOffset(string address)
            {
                //去掉V1025 前面的V
                //address = address.Substring(1);
                //I1.3地址的情况
                if (address.IndexOf('.') < 0)
                    return 0;
                else
                {
                    string[] temp = address.Split('.');
                    return Convert.ToInt32(temp[1]);
                }
            }
            Result result = new Result();
            try
            {
                Address = Address.Norm();
                switch (Address[0])
                {
                    case 'I':
                        SiemensStore = SiemensStore.I;
                        break;

                    case 'Q':
                        SiemensStore = SiemensStore.Q;
                        break;

                    case 'M':
                        SiemensStore = SiemensStore.M;
                        break;

                    case 'D':
                        SiemensStore = SiemensStore.DB;
                        string[] adds = Address.Split('.');
                        if (Address[1] == 'B')
                            DBNum = Convert.ToUInt16(adds[0].Substring(2));
                        else
                            DBNum = Convert.ToUInt16(adds[0].Substring(1));
                        //TODO
                        //addressInfo.BeginAddress = GetBeingAddress(address.Substring(address.IndexOf('.') + 1));
                        break;

                    case 'T':
                        SiemensStore = SiemensStore.T;
                        break;

                    case 'C':
                        SiemensStore = SiemensStore.C;
                        break;

                    case 'V':
                        SiemensStore = SiemensStore.DB;
                        DBNum = 1;
                        break;
                }
                //DB块
                if (Address[0] == 'D' && Address[1] == 'B')
                {
                    //DB1.0.0、DB1.4（非PLC地址）
                    var indexOfpoint = Address.IndexOf('.') + 1;
                    if (Address[indexOfpoint] >= '0' && Address[indexOfpoint] <= '9')//char的比较,666
                    {
                        StartByteAddress = GetBeingAddress(Address.Substring(indexOfpoint));
                        BitOffset = GetBitOffset(Address.Substring(indexOfpoint));
                    }
                    //DB1.DBX0.0、DB1.DBD4（标准PLC地址）
                    else
                    {
                        StartByteAddress = GetBeingAddress(Address.Substring(Address.IndexOf('.') + 4));
                        BitOffset = GetBitOffset(Address.Substring(Address.IndexOf('.') + 4));
                    }
                }
                //非DB块
                else
                {
                    //I0.0、V1004的情况（非PLC地址）
                    if (Address[1] >= '0' && Address[1] <= '9')
                    {
                        StartByteAddress = GetBeingAddress(Address.Substring(1));
                        BitOffset = GetBitOffset(Address.Substring(1));
                    }
                    //VB1004的情况（标准PLC地址）
                    else
                    {
                        StartByteAddress = GetBeingAddress(Address.Substring(2));
                        BitOffset = GetBitOffset(Address.Substring(2));
                    }
                }
            }
            catch (Exception ex)
            {
                result.IsSucceed = false;
                result.Err = $"地址[{Address}]解析异常，ConvertArg Err:{ex.Message}";
                result.Exception = ex;
                return result;
            }
            return result;
        }

        /// <summary>
        /// 西门子变量,地址格式如下:
        /// <para>DB1.DBX0.0、DB1.DBD4（标准PLC地址）</para>
        /// <para>VB1004的情况（标准PLC地址）</para>
        /// <para>DB1.0.0、DB1.4（非PLC地址）</para>
        /// <para>I0.0、V1004的情况（非PLC地址）</para>
        /// </summary>
        /// <param name="address">
        /// 格式如下:
        /// <para>DB1.DBX0.0、DB1.DBD4（标准PLC地址）</para>
        /// <para>VB1004的情况（标准PLC地址）</para>
        /// <para>DB1.0.0、DB1.4（非PLC地址）</para>
        /// <para>I0.0、V1004的情况（非PLC地址）</para>
        /// </param>
        /// <param name="dataType">数据类型</param>
        public VarableSiemens(string address, DataTypeEnum dataType)
        {
            DataType = dataType;
            Address = address.Norm();
            // AddressAnalysis().ShowResultConsole();
        }

        /// <summary>
        /// 西门子存储区
        /// </summary>
        [JsonProperty("存储区"), DisplayName("2.1存储区"), Category("变量信息")]
        public SiemensStore SiemensStore { get; set; } = SiemensStore.DB;

        /// <summary>
        /// 站号
        /// </summary>
        [JsonProperty("DB号"), DisplayName("2.2DB号"), Category("变量信息")]
        public ushort DBNum { get; set; } = 1;

        /// <summary>
        /// 变量地址
        /// <para>DB1.0.0、DB1.4（非PLC地址）</para>
        /// <para>DB1.DBX0.0、DB1.DBD4（标准PLC地址）</para>
        /// <para>I0.0、V1004的情况（非PLC地址）</para>
        /// <para>VB1004的情况（标准PLC地址）</para>
        /// <para></para>
        /// </summary>
        [JsonProperty("变量地址"), DisplayName("变量地址"), Category("变量信息")]
        public override string Address { get; set; } = "西门子地址";
    }

    /// <summary>
    /// 报文指令
    /// </summary>
    public class SiemensConstant
    {
        /// <summary>
        /// Head头读取长度
        /// </summary>
        public static readonly ushort InitHeadLength = 4;

        /// <summary>
        /// 第一次初始化指令交互报文
        /// </summary>
        public static readonly byte[] Command1 = new byte[22]
        {
            0x03,0x00,0x00,0x16,0x11,0xE0,0x00,0x00,
            0x00,0x01,0x00,0xC0,0x01,0x0A,0xC1,0x02,
            0x01,0x02,0xC2,0x02,0x01,0x00
        };

        /// <summary>
        /// 第二次初始化指令交互报文
        /// </summary>
        public static readonly byte[] Command2 = new byte[25]
        {
            0x03,0x00,0x00,0x19,0x02,0xF0,0x80,0x32,
            0x01,0x00,0x00,0x04,0x00,0x00,0x08,0x00,
            0x00,0xF0,0x00,0x00,0x01,0x00,0x01,0x01,0xE0
        };

        /// <summary>
        /// 第一次初始化指令交互报文
        /// </summary>
        public static readonly byte[] Command1_200Smart = new byte[22]
        {
            0x03,0x00,0x00,0x16,0x11,0xE0,0x00,0x00,
            0x00,0x01,0x00,0xC1,0x02,0x10,0x00,0xC2,
            0x02,0x03,0x00,0xC0,0x01,0x0A
        };

        /// <summary>
        /// 第二次初始化指令交互报文
        /// </summary>
        public static readonly byte[] Command2_200Smart = new byte[25]
        {
            0x03,0x00,0x00,0x19,0x02,0xF0,0x80,0x32,
            0x01,0x00,0x00,0xCC,0xC1,0x00,0x08,0x00,
            0x00,0xF0,0x00,0x00,0x01,0x00,0x01,0x03,0xC0
        };

        /// <summary>
        /// 第一次初始化指令交互报文
        /// </summary>
        public static readonly byte[] Command1_200 = new byte[]
        {
            0x03,0x00,0x00,0x16,0x11,0xE0,0x00,0x00,
            0x00,0x01,0x00,0xC1,0x02,0x4D,0x57,0xC2,
            0x02,0x4D,0x57,0xC0,0x01,0x09
        };

        /// <summary>
        /// 第二次初始化指令交互报文
        /// </summary>
        public static readonly byte[] Command2_200 = new byte[]
        {
            0x03,0x00,0x00,0x19,0x02,0xF0,0x80,0x32,
            0x01,0x00,0x00,0x00,0x00,0x00,0x08,0x00,
            0x00,0xF0,0x00,0x00,0x01,0x00,0x01,0x03,0xC0
        };
    }

    #endregion 派生的变量和变量组
}